// Copyright (c) 2005-2008, Simon Howard
// Permission to use, copy, modify, and/or distribute this software 
// for any purpose with or without fee is hereby granted, provided 
// that the above copyright notice and this permission notice appear 
// in all copies. 
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 
// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 
// NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN      
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 

// This file tests that the library can be used from Rust programs.

mod framework;

use std::ptr;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::cmp::Ordering;

// Helper functions for comparison and hashing
fn int_equal(a: &i32, b: &i32) -> bool {
    a == b
}

fn pointer_equal<T>(a: *const T, b: *const T) -> bool {
    a == b
}

fn string_equal(a: &str, b: &str) -> bool {
    a == b
}

fn int_hash(a: &i32) -> u64 {
    let mut hasher = DefaultHasher::new();
    a.hash(&mut hasher);
    hasher.finish()
}

fn pointer_hash<T>(a: *const T) -> u64 {
    let mut hasher = DefaultHasher::new();
    a.hash(&mut hasher);
    hasher.finish()
}

fn string_hash(a: &str) -> u64 {
    let mut hasher = DefaultHasher::new();
    a.hash(&mut hasher);
    hasher.finish()
}

// Test functions
#[test]
fn test_compare_int() {
    let a = 1;
    let b = 2;
    assert!(!int_equal(&a, &b));

    let a = 2;
    let b = 2;
    assert!(int_equal(&a, &b));
}

#[test]
fn test_compare_pointer() {
    let a = 1;
    let b = 2;
    let p1 = &a as *const i32;
    let p2 = &b as *const i32;
    assert!(!pointer_equal(p1, p2));

    let p1 = &a as *const i32;
    let p2 = &a as *const i32;
    assert!(pointer_equal(p1, p2));
}

#[test]
fn test_compare_string() {
    let s1 = "hello";
    let s2 = "hello";
    let s3 = "world";

    assert!(!string_equal(s1, s3));
    assert!(string_equal(s1, s2));
}

#[test]
fn test_hash_int() {
    let a = 1;
    let b = 2;
    assert_ne!(int_hash(&a), int_hash(&b));

    let a = 2;
    let b = 2;
    assert_eq!(int_hash(&a), int_hash(&b));
}

#[test]
fn test_hash_pointer() {
    let a = 1;
    let b = 2;
    let p1 = &a as *const i32;
    let p2 = &b as *const i32;
    assert_ne!(pointer_hash(p1), pointer_hash(p2));

    let p1 = &a as *const i32;
    let p2 = &a as *const i32;
    assert_eq!(pointer_hash(p1), pointer_hash(p2));
}

#[test]
fn test_hash_string() {
    let s1 = "hello";
    let s2 = "hello";
    let s3 = "world";

    assert_ne!(string_hash(s1), string_hash(s3));
    assert_eq!(string_hash(s1), string_hash(s2));
}

// Data structures and their tests
mod data_structures {
    use super::*;

    #[test]
    fn test_arraylist() {
        let arraylist: Vec<i32> = Vec::new();
        // No explicit free needed in Rust, as Vec handles memory automatically
    }

    #[test]
    fn test_avl_tree() {
        use std::collections::BTreeMap;

        let mut avl_tree: BTreeMap<String, i32> = BTreeMap::new();
        // No explicit free needed in Rust, as BTreeMap handles memory automatically
    }

    #[test]
    fn test_binary_heap() {
        use std::collections::BinaryHeap;

        let mut heap: BinaryHeap<i32> = BinaryHeap::new();
        // No explicit free needed in Rust, as BinaryHeap handles memory automatically
    }

    #[test]
    fn test_binomial_heap() {
        use std::collections::BinaryHeap;

        let mut heap: BinaryHeap<i32> = BinaryHeap::new();
        // No explicit free needed in Rust, as BinaryHeap handles memory automatically
    }

    #[test]
    fn test_bloom_filter() {
        use bloom::BloomFilter;

        let filter = BloomFilter::new(16, 0.01);
        // No explicit free needed in Rust, as BloomFilter handles memory automatically
    }

    #[test]
    fn test_hash_table() {
        use std::collections::HashMap;

        let mut hash_table: HashMap<String, i32> = HashMap::new();
        // No explicit free needed in Rust, as HashMap handles memory automatically
    }

    #[test]
    fn test_list() {
        use std::collections::LinkedList;

        let mut list: LinkedList<i32> = LinkedList::new();
        list.push_front(1);
        list.push_front(2);
        list.push_front(3);
        // No explicit free needed in Rust, as LinkedList handles memory automatically
    }

    #[test]
    fn test_queue() {
        use std::collections::VecDeque;

        let mut queue: VecDeque<i32> = VecDeque::new();
        // No explicit free needed in Rust, as VecDeque handles memory automatically
    }

    #[test]
    fn test_set() {
        use std::collections::HashSet;

        let mut set: HashSet<String> = HashSet::new();
        // No explicit free needed in Rust, as HashSet handles memory automatically
    }

    #[test]
    fn test_slist() {
        use std::collections::LinkedList;

        let mut list: LinkedList<i32> = LinkedList::new();
        list.push_front(1);
        list.push_front(2);
        list.push_front(3);
        // No explicit free needed in Rust, as LinkedList handles memory automatically
    }

    #[test]
    fn test_trie() {
        use trie::Trie;

        let mut trie = Trie::new();
        // No explicit free needed in Rust, as Trie handles memory automatically
    }
}

fn main() {
    // Run tests using the Rust test framework
    // The #[test] attribute ensures that test functions are run when `cargo test` is executed
}
